#include <iostream>
#include <mutex>
#include <thread>
#include <memory>
template <class T>
class SmartPtr
{
public:
    SmartPtr(T *ptr = nullptr)
        : _ptr(ptr)
    {
    }
    ~SmartPtr()
    {
        if (_ptr)
        {
            delete _ptr;
        }
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }

private:
    T *_ptr;
};
struct Date
{
    int _year;
    int _month;
    int _day;
};
void test()
{
    SmartPtr<int> sp1(new int);
    *sp1 = 10;
    std::cout << *sp1 << std::endl;
    SmartPtr<Date> sp2(new Date);
    sp2->_year = 2025;
    sp2->_month = 11;
    sp2->_day = 3;
    std::cout << (sp2->_year) << " " << (sp2->_month) << " " << (sp2->_day) << std::endl;
}
template <class T>
class AutoPtr
{
public:
    AutoPtr(T *ptr = nullptr)
        : _ptr(ptr)
    {
    }
    ~AutoPtr()
    {
        if (_ptr)
        {
            delete _ptr;
        }
    }
    AutoPtr(AutoPtr<T> &ap)
        : _ptr(ap._ptr)
    {
        ap._ptr = nullptr;
    }
    AutoPtr<T> &operator=(AutoPtr<T> &ap)
    {
        if (this != &ap)
        {
            if (_ptr)
                delete _ptr;
            _ptr = ap._ptr;
            ap._ptr = nullptr;
        }
        return *this;
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }

private:
    T *_ptr;
};
void test1()
{
    AutoPtr<int> ap(new int);
    *ap = 10;
    std::cout << *ap << std::endl;
    AutoPtr<int> ap1(ap);
    // *ap = 20;
}
template <class T>
class UniquePtr
{
public:
    UniquePtr(T *ptr = nullptr)
        : _ptr(ptr)
    {
    }
    ~UniquePtr()
    {
        if (_ptr)
        {
            delete _ptr;
        }
    }
    UniquePtr(UniquePtr<T> &up) = delete;
    UniquePtr<T> &operator=(UniquePtr &up) = delete;
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }

private:
    T *_ptr;
};
void test2()
{
    UniquePtr<int> up(new int);
    *up = 10;
    std::cout << *up << std::endl;
    // UniquePtr<int> up1(up);
    UniquePtr<int> up1(new int);
    // up1 = up;
}
template <class T>
class SharePtr
{
public:
    SharePtr(T *ptr = nullptr)
        : _ptr(ptr), _pRefCount(new int(1)), _pMutex(new std::mutex)
    {
    }
    ~SharePtr()
    {
        Release();
    }
    SharePtr(const SharePtr<T> &sp)
        : _ptr(sp._ptr), _pRefCount(sp._pRefCount), _pMutex(sp._pMutex)
    {
        AddRefCount();
    }
    SharePtr<T> &operator=(const SharePtr<T> &sp)
    {
        if (this != &sp)
        {
            Release();
            _ptr = sp._ptr;
            _pRefCount = sp._pRefCount;
            _pMutex = sp._pMutex;
            AddRefCount();
        }
        // if (_ptr != sp._ptr)
        // {
        //     Release();
        //     _ptr = sp._ptr;
        //     _pRefCount = sp._pRefCount;
        //     _pMutex = sp._pMutex;
        //     AddRefCount();
        // }
        return *this;
    }
    void AddRefCount()
    {
        _pMutex->lock();
        ++(*_pRefCount);
        _pMutex->unlock();
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }
    int UseCount()
    {
        return *_pRefCount;
    }
    T *Get() const
    {
        return _ptr;
    }

private:
    void Release()
    {
        bool deleteflag = false;
        _pMutex->lock();
        if (--(*_pRefCount) == 0)
        {
            delete _pRefCount;
            _pRefCount = nullptr;
            delete _ptr;
            _ptr = nullptr;
            deleteflag = true;
        }
        _pMutex->unlock();
        if (deleteflag == true)
        {
            delete _pMutex;
            _pMutex = nullptr;
        }
    }

private:
    int *_pRefCount;
    T *_ptr;
    std::mutex *_pMutex;
};
void test3()
{
    SharePtr<int> sp1(new int(10));
    SharePtr<int> sp2(sp1);
    *sp2 = 20;
    std::cout << sp1.UseCount() << std::endl;
    std::cout << sp2.UseCount() << std::endl;
    SharePtr<int> sp3(new int(10));
    sp2 = sp3;
    std::cout << sp1.UseCount() << std::endl;
    std::cout << sp2.UseCount() << std::endl;
    std::cout << sp3.UseCount() << std::endl;
    sp1 = sp3;
    std::cout << sp1.UseCount() << std::endl;
    std::cout << sp2.UseCount() << std::endl;
    std::cout << sp3.UseCount() << std::endl;
}
template <class T>
class WeakPtr
{
public:
    WeakPtr() = default;
    WeakPtr(const SharePtr<T> &sp)
        : _ptr(sp.Get())
    {
    }
    WeakPtr<T> &operator=(const SharePtr<T> &sp)
    {
        _ptr = sp.Get();
        return *this;
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }

private:
    T *_ptr;
};
struct ListNode
{
    // 解决循环引用问题
    int _data;
    WeakPtr<ListNode> _prev;
    WeakPtr<ListNode> _next;
    ~ListNode() { std::cout << "~ListNode()" << std::endl; }
};
void test4()
{
    SharePtr<ListNode> node1(new ListNode);
    SharePtr<ListNode> node2(new ListNode);
    std::cout << node1.UseCount() << std::endl;
    std::cout << node2.UseCount() << std::endl;
    node1->_next = node2;
    node2->_prev = node1;
    std::cout << node1.UseCount() << std::endl;
    std::cout << node2.UseCount() << std::endl;
}
int main(int argc, char *argv[])
{
    // test();
    // test1();
    // test2();
    // test3();
    test4();
    return 0;
}